=begin

This file is part of the RSIF project, http://rsif.googlecode.com

Copyright (c) 2009-2009 Roberto Dario Seminara <robertodarioseminara@gmail.com>

rsif is free software: you can redistribute it and/or modify
it under the terms of the gnu general public license as published by
the free software foundation, either version 3 of the license, or
(at your option) any later version.

rsif is distributed in the hope that it will be useful,
but without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.  see the
gnu general public license for more details.

you should have received a copy of the gnu general public license
along with rsif.  if not, see <http://www.gnu.org/licenses/>.
=end

require "context"
require "logger/contextlogger"
require "modules/factory"
require "modules/provideinfo"

module Rsif
module Core
module Modules

class Module

  # atributos que se definen en el modulo (la clase) al heredar
  # de la clase Module

  attr_accessor	:framework

  include Rsif::Core::Logging
  class << self
	include Rsif::Core::Logging
  end

  module ModuleAttributes

      def dependencies
	if @dependencies == nil
	  @dependencies = []
	end
	@dependencies + self.superclass.dependencies
      end

      def add_dependencie( a )
	@dependencies = [] if @dependencies == nil
	@dependencies << a
      end

      def included(klass)
	dependencies = [] if dependencies == nil
      end

      def can_instantiate
	Module.can_instantiate(self)
      end

      def create( params = nil)
	ins = self.new

		begin
		ins.initialize_params( params )
		rescue
		end
	ins
	rescue	# TODO: especificar la excepcion de wrong parameters number
	self.new()
      end
  end

  class << self
	attr_accessor	:module_load_proc
  end

  # acada vez que una clase extiende de esta, se le mixea el modulo ModuleAttributes
  def self.inherited( klass )
	logger.debug "module #{self} inherited by #{klass}"

	Module.module_load_proc.call(klass) if Module.module_load_proc

	klass.extend ModuleAttributes
  end

  # el contexto que usan todos los modulos es una variable de clase
  # esto ocurre porque muchos metodos de clase necesitan acceder a el
  def self.provideinfo
    ProvideInfo.instance
  end

  def self.context
    Context.instance
  end

  def context
    Module.context
  end

  # define si puede instanciar el objeto, para esto recorre las dependencias
  # y verifica que se cumplan
  # FIXME: separar la logica de verificacion de instanciacion de la ejecucion
  # automatica de modulos que proveen

  def self.can_instantiate( klass )
    logger.debug "dependencies of #{klass} : #{klass.dependencies.join(", ")}"
    
    # para cada dependencia, buscar en la tabla de simbolos, si 
    # esta definido ese simbolo

    ret = 1

    klass.dependencies.each do |dep|
	if context.symbol(dep) == nil
	  # ejecuta los modulos que proveen el simbolo hasta 
	  # obtenerlo
	  ret = nil
	  logger.error "checking dependencie #{dep} for class #{klass}: FAIL"
	else
	  logger.debug "checking dependencie #{dep} for class #{klass}: OK"
	end
    end


    ret
  end

  # SUGAR SYNTAX: permite definir facilmente a cualquier modulo
  # que su instancia sirve como simbolo
  def self.instance_provide( symbol )
    # para eso, se crea una pseudo clase que se registra como
    # proveedora se ese simbolo, internamente, el metodo
    # run de la clase instancia el objeto y define el simbolo con el
    pseudo = PseudoFactoryClass.new(symbol,self,self.context)
    self.provideinfo.provide(symbol,pseudo)
  end

  # SUGAR SYNTAX: permite definir facilmente a cualquier modulo
  # como proveedor de un simbolo
  def self.provide( symbol )
    # self es la clase que llama a provide
    self.provideinfo.provide( symbol, self )
  end

  # SUGAR SYNTAX: permite definir facilmente una dependencia
  # para un modulo especifico
  def self.depends_on( symbol )
     self.add_dependencie(symbol)
  end

  # el modulo generico no tiene ningun tipo de dependencia
  # simbolica
  def self.dependencies
    []
  end

  # permite definir un metodo para verificar la validez
  # de la instancia de un modulo
  def good
  # por default, si no se sobreescribe el metodo good, devuelve 
  # verdadero, es decir, que el objeto se puede usar
    1
  end

  # funciones para leer y escribir los simbolos
  def symbol( s )
    context.symbol(s)
  end

  def define_symbol( s, value )
    context.define_symbol(s, value)
  end

end

end
end
end
